package com.olap.starter.util;

import com.alibaba.fastjson.JSONObject;
import com.olap.starter.core.exception.OnlineException;
import com.olap.starter.util.StringUtils;
import org.springframework.util.Assert;

import java.lang.reflect.Field;
import java.util.*;

/**
 * @author WBG
 * @date 2022/6/13 9:17
 * @describe 对象工具类
 */
public class ObjectUtils {


    /**
     * 将Map中的key由下划线转换为驼峰
     *
     * @param map
     * @return
     */
    public static Map<String, Object> formatHumpName(Map<String, Object> map) {
        Map<String, Object> newMap = new HashMap<>();
        Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, Object> entry = it.next();
            String key = entry.getKey();
            String newKey = StringUtils.toCamelCase(key);
            newMap.put(newKey, entry.getValue());
        }
        return newMap;
    }

    /**
     * 将Map中的key由下划线转换为驼峰
     *
     * @param list
     * @return
     */
    public static List<Map<String, Object>> formatHumpName(List<Map<String, Object>> list) {
        if (list == null || list.size() == 0) {
            return list;
        }
        List<Map<String, Object>> newList = new ArrayList<>();
        for (Map<String, Object> map : list) {
            Map<String, Object> newMap = new HashMap<String, Object>();
            Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator();
            while (it.hasNext()) {
                Map.Entry<String, Object> entry = it.next();
                String key = entry.getKey();
                String newKey = StringUtils.toCamelCase(key);
                newMap.put(newKey, entry.getValue());
            }
            newList.add(newMap);
        }

        return newList;
    }

    /**
     * 将object中的key由下划线转换为驼峰
     *
     * @param list
     * @return
     */
    public static List<Map<String, Object>> listObjectToListMap(List list) {
        if (list == null || list.size() == 0) {
            return null;
        }
        List<Map<String, Object>> newList = new ArrayList<>();
        for (Object o : list) {
            newList.add(objectToMap(o));
        }
        return newList;
    }
    /**
     * 将object中的key由下划线转换为驼峰
     *
     * @param list
     * @return
     */
    public static <T> List<T> listMapToListObject(List<Map> list,Class<T> beanClass) {
        if (list == null || list.size() == 0) {
            return null;
        }
        List<T> newList = new ArrayList<>();
        for (Map o : list) {
            newList.add((T)mapToObject(o, beanClass));
        }
        return newList;
    }
    /**
     * @param source              资源对象
     * @param filed               字段  逗号分割
     * @param filedOpenHumpSource 是否字段打开驼峰命名对应资源   比如true--  对象是myName,字段可以是my_name
     * @param resultKayFiled      是否返回结果用file作为key  true 返回参数key根据传入字段  否则使用对象字段
     * @return
     */
    public static Map<String, Object> getPropertiesToMap(Object source, String filed, boolean filedOpenHumpSource, boolean resultKayFiled) {
        Map<String, Object> map = new HashMap<>();
        List<String> filedList = Arrays.asList(filed.split(","));
        for (Field field : source.getClass().getDeclaredFields()) {
            String name = field.getName();
            if (filedList.contains(name)) {
                field.setAccessible(true);
                try {
                    map.put(name, field.get(source));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                    throw new OnlineException("属性设值异常 [" + name + "]");
                }
            }
        }
        return map;
    }

    /**
     * 复制属性  默认不使用驼峰命名
     *
     * @param source 源对象
     * @param target 目标对象
     * @param filed  复制的字段  逗号分科  如 id,name
     * @return
     */
    public static Object copyProperties(Object source, Object target, String filed) {
        return copyProperties(source, target, filed, false);
    }

    /**
     * 复制map对象
     * @explain 将paramsMap中的键值对全部拷贝到resultMap中；
     * paramsMap中的内容不会影响到resultMap（深拷贝）
     * @param source
     *     被拷贝对象
     * @param target
     *     拷贝后的对象
     */
    public static Map mapCopy(Map source, Map target) {
        if (target == null) target = new HashMap();
        if (source == null) return null;

        Iterator it = source.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry entry = (Map.Entry) it.next();
            Object key = entry.getKey();
            target.put(key, source.get(key) != null ? source.get(key) : "");
        }
        return target;
    }

    /**
     * 复制属性
     *
     * @param source   源对象
     * @param target   目标对象
     * @param filed    复制的字段  逗号分科  如 id,name   id:id,name:name
     * @param openHump 打开驼峰命名  myName:MY_NAME
     * @return
     */
    public static Object copyProperties(Object source, Object target, String filed, boolean openHump) {
        Assert.notNull(source, "Source must not be null");
        Assert.notNull(target, "Target must not be null");
        Map<String, String> sourceToTargetFiledMaps = getSourceToTargetFiledMaps(filed, openHump);
        Field[] sourceFiled = source.getClass().getDeclaredFields();
        for (String key : sourceToTargetFiledMaps.keySet()) {
            Field field = null;
            for (Field f : sourceFiled) {
                if (f.getName().equals(key)) {
                    field = f;
                    break;
                }
            }
            if (field == null) {
                throw new OnlineException("source 没有找到属性 [" + key + "]");
            }
            String targetFileName = sourceToTargetFiledMaps.get(key);
            Field targetFile = getDeclaredField(target, targetFileName);
            targetFile.setAccessible(true);
            field.setAccessible(true);
            try {
                targetFile.set(target, field.get(source));
            } catch (IllegalAccessException e) {
                e.printStackTrace();
                throw new OnlineException("属性设值异常 [" + targetFileName + "]");
            }
        }
        return target;
    }

    private static Map<String, String> getSourceToTargetFiledMaps(String filed, boolean openHump) {
        if (StringUtils.isBlank(filed)) {
            throw new OnlineException("filed must not be null");
        }
        Map<String, String> sourceFiledToTargetFiled = new HashMap<>();
        for (String s : filed.split(",")) {
            String[] split = s.split(":");
            String f1 = openHump ? StringUtils.toCamelCase(split[0]) : split[0];
            String f2 = split.length == 1 ? f1 : openHump ? StringUtils.toCamelCase(split[1]) : split[1];
            sourceFiledToTargetFiled.put(f1, f2);
        }
        return sourceFiledToTargetFiled;
    }

    private static Field getDeclaredField(Object obj, String targetFileName) {
        try {
            return obj.getClass().getDeclaredField(targetFileName);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
            throw new OnlineException("没有字段 [" + targetFileName + "]");
        }
    }

    /**
     * map转java对象
     * @param map
     * @param beanClass
     * @return
     * @throws Exception
     */
    public static <T> T mapToObject(Map<String, Object> map, Class<T> beanClass){
        return JSONObject.parseObject(JSONObject.toJSONString(map), beanClass);

    }

    /**
     * java对象转map
     * @param obj
     * @return
     */
    public static Map<String, Object> objectToMap(Object obj) {
        return JSONObject.parseObject(JSONObject.toJSONString(obj));

    }

}
